#!/usr/bin/env python
#
#       Data_tab.py
#       
#       Copyright 2009 Brandon Invergo <brandon@brandoninvergo.com>
#       
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#       
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#       
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

import sys

try:
    import pygtk
    #tell pyGTK, if possible, that we want GTKv2
    pygtk.require("2.0")
except:
    #Some distributions come with GTK2, but not pyGTK
    pass

try:
    import gtk
    import gtk.glade
    
except:
    print "You need to install pyGTK or GTKv2 ",
    print "or set your PYTHONPATH correctly."
    print "try: export PYTHONPATH=",
    print "/usr/local/lib/python2.2/site-packages/"
    sys.exit(1)

from gobject import TYPE_INT, TYPE_STRING, TYPE_OBJECT, TYPE_PYOBJECT
import Error_dialog
from MajeRe_Engine import REngException
import Data_group

class Add_data_set_window:
    
    def on_name_entry(self, widget):
        self.on_add(widget)
    
    def on_cancel(self, widget):
        self.window.hide()
        
    def on_edit(self, widget):
        name = self.data_set_name.get_text()
        name = name.replace(" ", ".")
        if name == "":
            self.error.show_error("Error", "Enter a name for the data set.")
            return
        self.window.hide()
        try:
            self.main_window.do_R_command("%s <- data.frame()"%name, False)
        except REngException, error_msg:
            self.error.show_error("R engine error", error_msg.parameter)
        try:
            self.main_window.do_R_command("fix(%s)"%name, True)
        except REngException, error_msg:
            self.error.show_error("R engine error", error_msg.parameter)        
    
    def on_import(self, widget):
        name = self.data_set_name.get_text()
        name = name.replace(" ", ".")
        if name == "":
            self.error.show_error("Error", "Enter a name for the data set.")
            return
        self.import_data_dialog.show(name)
        self.window.hide()
    
    def show(self):
        self.data_set_name.set_text("")
        self.window.show()
    
    def __init__(self, parent_window, glade_gui):
        self.glade_gui = glade_gui
        self.parent_window = parent_window
        self.main_window = parent_window.main_window
        self.window = self.glade_gui.get_widget("Add_data_set")
        self.data_set_name = self.glade_gui.get_widget("Add_data_set_name")
        self.error = Error_dialog.Error_dialog()
        self.import_data_dialog = Import_data(self.parent_window, self.glade_gui)

        callbacks = {"on_Add_data_set_cancel" : self.on_cancel,\
            "on_Add_data_set_edit" : self.on_edit,\
            "on_Add_data_set_import" : self.on_import,\
            "on_Add_data_set_name" : self.on_name_entry}
        self.glade_gui.signal_autoconnect(callbacks)
        

class Import_data:
    def on_cancel(self, widget):
        self.dialog.hide()
        
    def on_file_activated(self, widget):
        self.open_file()
    
    def on_open(self, widget):
        self.open_file()
        
    def open_file(self):
        filename = self.dialog.get_filename()
        try:
            res = self.parent_window.main_window.do_R_command("%s <- read.delim(\"%s\")"%(self.name, filename),\
                True)
        except REngException, error_msg:
            self.error.show_error("R engine error", error_msg.parameter)
            return
        self.dialog.hide()
    
    def show(self, name):
        self.name = name
        self.dialog.show()
    
    def __init__(self, parent_window, glade_gui):
        self.dialog = glade_gui.get_widget("Import_data_file_chooser")
        self.parent_window= parent_window
        self.error = Error_dialog.Error_dialog()

        callbacks = {"on_import_data_cancel_button" : self.on_cancel,\
            "on_Import_data_file_activated": self.on_file_activated,\
            "on_import_data_open_button" : self.on_open}
        glade_gui.signal_autoconnect(callbacks)
        


class Add_data_group_window:    
    def show(self, objects, group):
        self.edit_group = group
        self.objects_treestore = objects
        self.objects_treeview.set_model(self.objects_treestore)
        self.members_liststore.clear()
        if self.edit_group != None:
            self.data_group_name.set_text(self.edit_group.name)
            for member in self.edit_group.member_list:
                self.members_liststore.append([member.name, member.id, member.role, member.aux])
        else:
            self.data_group_name.set_text("")
        self.window.show()
        
    def on_cancel(self, widget):
        self.window.hide()
        
    def on_data_group_name(self, widget):
        self.on_add(widget)
        
    def on_add(self, widget):
        name = self.data_group_name.get_text()
        if name == "":
            self.error.show_error("Error", "Enter a name for the data set.")
            return
        if self.members_liststore.get_iter_first() == None:
            self.error.show_error("Error", "You must add at least one member to the group.")
            return
        
        if self.edit_group == None:
            data_group = Data_group.Data_group(name)
            self.members_liststore.foreach(self.add_member_to_group, data_group)
            self.parent_window.add_data_group(data_group)
            
        else:
            old_name = self.edit_group.name
            self.edit_group.name = name
            self.edit_group.clear_members()
            self.edit_group.clear_dict()
            self.members_liststore.foreach(self.add_member_to_group, self.edit_group)
            self.parent_window.edit_data_group(self.edit_group, old_name)
        self.window.hide()
            
    def add_member_to_group(self, model, path, iter, data_group):
        memb_name = model.get_value(iter, 0)
        memb_id = model.get_value(iter, 1)
        memb_role = model.get_value(iter, 2)
        memb_aux = model.get_value(iter, 3)
        memb_n = self.main_window.r_eng.get_length(memb_id)
        data_group.add_member(memb_name, memb_id, memb_role, memb_aux, memb_n)
        return False
           
    def on_member_activated(self, view, path, column):
        iter = self.objects_treestore.get_iter(path)
        if self.objects_treestore.iter_depth(iter) > 0 and \
            self.objects_treestore.iter_n_children(iter) == 0:
            self.on_remove_member(view)
    
    def on_remove_member(self, widget):
        cursor = self.members_treeview.get_cursor()[0]
        tree_iter = self.members_liststore.get_iter(cursor)
        self.members_liststore.remove(tree_iter)
        self.members_treeview.set_cursor(cursor)
        
    def on_obj_activated(self, view, path, column):
        iter = self.objects_treestore.get_iter(path)
        if self.objects_treestore.iter_depth(iter) > 0 and \
            self.objects_treestore.iter_n_children(iter) == 0:
            self.on_include_object(view)
        else:
            self.objects_treeview.expand_row(path, False)
        
    def on_include_object(self, widget):
        cursor = self.objects_treeview.get_cursor()[0]
        tree_iter = self.objects_treestore.get_iter(cursor)
        object_name, object_id, object_type = self.objects_treestore.get(tree_iter, 0, 1, 2)
        role_list = self.build_role_list(object_name, object_type)
        self.show_role_dialog(object_name, object_id, object_type, role_list)
                
    def build_role_list(self, object_name, object_type):
        role_list = []
        if object_type == "Factor":
            levels = self.main_window.r_eng.get_levels(object_name)
            num_levels = len(levels)
            role_list.append("Fixed Factor")
            role_list.append("Random Factor")
            role_list.append("Response")
        if object_type == "Double":
            role_list.append("Covariate")
            role_list.append("Probabilities")
            role_list.append("Response")
            role_list.append("Sample Data")
        if object_type == "Integer":
            if self.main_window.r_eng.valid_counts(object_name):
                role_list.append("Counts")
            role_list.append("Covariate")
            role_list.append("Fixed Factor")
            role_list.append("Random Factor")
            role_list.append("Response")
            role_list.append("Sample Data")         
        return role_list
                
    def show_role_dialog(self, object_name, object_id, object_type, role_list):
        self.glade_gui.get_widget("member_role_name_label").set_text(object_name)        
        self.glade_gui.get_widget("member_role_type_label").set_text(object_type)
        aux_label = self.glade_gui.get_widget("member_role_aux_label")
        aux_label.set_text("")
        
        role_hbox = self.glade_gui.get_widget("member_role_hbox")
        role_hbox_children = role_hbox.get_children()
        if len(role_hbox_children) == 2:
            role_hbox.remove(role_hbox_children[1])
        
        aux_hbox =  self.glade_gui.get_widget("member_role_aux_hbox")
        aux_hbox_children = aux_hbox.get_children()
        if len(aux_hbox_children) == 2:
            aux_hbox.remove(aux_hbox_children[1])    
        
        self.role_combo = gtk.combo_box_new_text()
        for role in role_list:
            self.role_combo.append_text(role)
        self.role_combo.set_active(0)
        self.role_selected(self.role_combo, object_name, object_type)
        role_hbox.pack_end(self.role_combo)
        self.role_combo.connect("changed", self.role_selected, object_name, object_type)
        self.role_combo.show()
        role_hbox.show()
        response = self.member_role_dialog.run()
        
        if response == gtk.RESPONSE_OK:
            aux_hbox = self.glade_gui.get_widget("member_role_aux_hbox")
            aux_hbox_children = aux_hbox.get_children()
            
            if len(aux_hbox_children) == 1:
                self.role_aux_info = None
            else:
                self.role_aux_info = aux_hbox_children[1]
                    
            role = self.role_combo.get_active_text()
            if type(self.role_aux_info) == type(gtk.Label()):
                aux = self.role_aux_info.get_text()
                if role == "Fixed Factor" or role == "Random Factor":
                    aux = aux.split(", ")
            else: 
                if type(self.role_aux_info) == type(gtk.ComboBox()):
                    aux = self.role_aux_info.get_active_text()
                else: 
                    if self.role_aux_info == None:
                        aux = None
            self.members_liststore.append([object_name, object_id, role, aux])
        self.member_role_dialog.hide()
        
    def role_selected(self, role_combo, object_name, object_type):
        aux_label = self.glade_gui.get_widget("member_role_aux_label")
        aux_hbox =  self.glade_gui.get_widget("member_role_aux_hbox")
        aux_hbox_children = aux_hbox.get_children()
        if len(aux_hbox_children) == 2:
            aux_hbox.remove(aux_hbox_children[1])    
        selected_role = role_combo.get_active_text()
        if object_type == "Factor":
            if selected_role == "Fixed Factor" or selected_role == "Random Factor":
                levels = self.main_window.r_eng.get_levels(object_name)
                levels_str = ", ".join(levels)
                levels_label = gtk.Label(levels_str)
                levels_label.set_line_wrap(True)
                aux_label.set_text("Levels:  ")
                aux_hbox.pack_end(levels_label)
                levels_label.show()
            if selected_role == "Response":
                aux_label.set_text("Distribution:  ")
                distributions = gtk.combo_box_new_text()
                distributions.append_text("Binomial")
                distributions.append_text("Quasibinomial")
                aux_hbox.pack_end(distributions)
                distributions.set_active(0)
                distributions.show()
        if object_type == "Double":
            if selected_role == "Response" or selected_role == "Sample Data":
                aux_label.set_text("Distribution:  ")
                distributions = gtk.combo_box_new_text()
                distributions.append_text("Unknown")
                distributions.append_text("Normal")
                distributions.append_text("Quasi")
                distributions.append_text("Gamma")
                distributions.append_text("Inverse Gaussian")
                aux_hbox.pack_end(distributions)
                distributions.set_active(0)
                distributions.show()
        if object_type == "Integer":
            if selected_role == "Response" or selected_role == "Sample Data":
                aux_label.set_text("Distribution:  ")
                distributions = gtk.combo_box_new_text()
                distributions.append_text("Unknown")
                distributions.append_text("Normal")
                distributions.append_text("Poisson")
                distributions.append_text("Quasipoisson")
                distributions.append_text("Binomial")
                distributions.append_text("Quasibinomial")
                distributions.append_text("Gamma")
                distributions.append_text("Inverse Gaussian")
                aux_hbox.pack_end(distributions)
                distributions.set_active(0)
                distributions.show()
            if selected_role == "Fixed Factor" or selected_role == "Random Factor":
                aux_label.set_text("Levels:  ")
                object_name_fact = "as.factor(%s)"%object_name
                levels = self.main_window.r_eng.get_levels(object_name_fact)
                levels_str = ", ".join(levels)
                levels_label = gtk.Label(levels_str)
                levels_label.set_line_wrap(True)
                aux_hbox.pack_end(levels_label)
                levels_label.show()
            if selected_role == "Counts":
                aux_label.set_text("")
                aux_hbox_children = aux_hbox.get_children()
                if len(aux_hbox_children) == 2:
                    aux_hbox.remove(aux_hbox_children[1])
                
    def on_member_selected(self, widget):
        cursor = self.members_treeview.get_cursor()[0]
        if cursor == None:
            self.member_rem_button.set_sensitive(False)
        else:
            tree_iter = self.members_liststore.get_iter(cursor)
            self.member_rem_button.set_sensitive(True)
        
    def on_obj_selected(self, widget):
        cursor = self.objects_treeview.get_cursor()[0]
        tree_iter = self.objects_treestore.get_iter(cursor)
        if self.objects_treestore.iter_n_children(tree_iter) == 0 and \
            self.objects_treestore.iter_depth(tree_iter) > 0:
            self.object_incl_button.set_sensitive(True)
        else:
            self.object_incl_button.set_sensitive(False)

    def on_member_role(self, widget, path, new_text, store, tree):
        cursor = tree.get_cursor()[0]
        tree_iter = store.get_iter(cursor)
        store.set_value(tree_iter, 1, new_text)
    
    def objects_namecol_func(self, column, cell, model, iter):
        if model.iter_parent(iter) == None:
            name = model.get_value(iter, 0)
            cell.set_property('markup', "<b>" + name + "</b>")
        return
    
    def __init__(self, parent_window, main_window, glade_gui):
        self.parent_window = parent_window
        self.main_window = main_window
        self.glade_gui = glade_gui
        self.window = self.glade_gui.get_widget("Add_data_group")
        self.object_incl_button = self.glade_gui.get_widget("Add_data_group_incl")
        self.member_rem_button = self.glade_gui.get_widget("Add_data_group_rem")  
        self.data_group_name = self.glade_gui.get_widget("Data_group_name")
        self.member_role_dialog = self.glade_gui.get_widget("member_role_dialog")
        self.member_role_dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
        self.member_role_dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
        self.error = Error_dialog.Error_dialog()
                
        self.objects_treeview = glade_gui.get_widget("Add_data_group_obj_tree")
        objects_namecol = gtk.TreeViewColumn("Name")
        self.objects_treeview.append_column(objects_namecol)
        objects_namecell = gtk.CellRendererText()
        objects_namecol.pack_start(objects_namecell, True)
        objects_namecol.set_cell_data_func(objects_namecell, self.objects_namecol_func)

        objects_idcol = gtk.TreeViewColumn("ID")
        self.objects_treeview.append_column(objects_idcol)
        objects_idcell = gtk.CellRendererText()
        objects_idcol.pack_start(objects_idcell, True)

        objects_typecol = gtk.TreeViewColumn("Role")
        self.objects_treeview.append_column(objects_typecol)
        objects_typecell = gtk.CellRendererText()
        objects_typecol.pack_start(objects_typecell, True)
                
        objects_ncol = gtk.TreeViewColumn("n")
        self.objects_treeview.append_column(objects_ncol)
        objects_ncell = gtk.CellRendererText()
        objects_ncol.pack_start(objects_ncell, True)
        objects_namecol.add_attribute(objects_namecell, 'text', 0)
        objects_idcol.add_attribute(objects_idcell, 'text', 1)
        objects_typecol.add_attribute(objects_typecell, 'text', 2)
        objects_ncol.add_attribute(objects_ncell, 'text', 3)
    
        self.members_liststore = gtk.ListStore(TYPE_STRING, TYPE_STRING, \
            TYPE_STRING, TYPE_PYOBJECT)
        self.members_treeview = glade_gui.get_widget("Add_data_group_member_tree")
        self.members_treeview.set_model(self.members_liststore)
        member_namecol = gtk.TreeViewColumn("Name")
        self.members_treeview.append_column(member_namecol)
        member_namecell = gtk.CellRendererText()
        member_namecol.pack_start(member_namecell, True)
        member_namecol.add_attribute(member_namecell, 'text', 0)

        member_idcol = gtk.TreeViewColumn("ID")
        self.members_treeview.append_column(member_idcol)
        member_idcell = gtk.CellRendererText()
        member_idcol.pack_start(member_idcell, True)
        member_idcol.add_attribute(member_idcell, 'text', 1)
        
        member_rolecell = gtk.CellRendererText()
        member_rolecol = gtk.TreeViewColumn("Role", member_rolecell)
        member_rolecol.add_attribute(member_rolecell, 'text', 2)
        self.members_treeview.append_column(member_rolecol)
        
        callbacks = {"on_Add_data_group_incl" : self.on_include_object,\
            "on_Add_data_group_rem" : self.on_remove_member,\
            "on_Add_data_group_add" : self.on_add,\
            "on_Add_data_group_cancel" : self.on_cancel,\
            "on_Add_data_group_member_tree_cursor_changed" : self.on_member_selected,\
            "on_Add_data_group_obj_tree_cursor_changed" : self.on_obj_selected,\
            "on_Add_data_group_obj_tree_row_activated" : self.on_obj_activated,\
            "on_Add_data_group_member_tree_row_activated" : self.on_member_activated,\
            "on_Data_group_name" : self.on_data_group_name}
        self.glade_gui.signal_autoconnect(callbacks)

class Data_tab:
    data_objects = set()
    
    def on_data_objects_add(self, widget):
        self.add_data_sets_window.show()

    def on_data_objects_remove(self, widget):
        cursor = self.dt_treeview.get_cursor()[0]
        if cursor == None:
            return
        tree_iter = self.dt_treestore.get_iter(cursor)
        object_id = self.dt_treestore.get_value(tree_iter,1)
        try:
            self.main_window.r_eng.delete_object(object_id)
        except REngException, error_msg:
            self.error.show_error("Error", "Could not delete object")
        else:
            self.update_data_view()
            
    def on_data_objects_edit(self, widget):
        cursor = self.dt_treeview.get_cursor()[0]
        if cursor == None:
            return
        tree_iter = self.dt_treestore.get_iter(cursor)
        object_name = self.dt_treestore.get_value(tree_iter,0)
        try:
            self.main_window.r_eng.R("fix(%s)"%object_name)
        except REngException, error_msg:
            self.show_error("Error", "Could not access object")
        else:
            self.update_data_view()
            
    def on_data_groups_activated(self, view, path, column):
        if self.dg_treeview.row_expanded(path):
            self.dg_treeview.collapse_row(path)
        else:
            self.dg_treeview.expand_row(path, False)

    def on_data_objects_activated(self, view, path, column):
        if self.dt_treeview.row_expanded(path):
            self.dt_treeview.collapse_row(path)
        else:
            self.dt_treeview.expand_row(path, False)
            
    def on_data_groups_remove(self, widget):
        cursor = self.dg_treeview.get_cursor()[0]
        if cursor == None:
            return
        tree_iter = self.dg_treestore.get_iter(cursor)
        self.dg_treestore.remove(tree_iter)
        
    def on_data_groups_add(self, widget):
        self.add_data_group_window.show(self.dt_treestore, None)
        
    def on_data_groups_edit(self, widget):
        cursor = self.dg_treeview.get_cursor()[0]
        iter = self.dg_treestore.get_iter(cursor)
        group = self.dg_treestore.get_value(iter, 4)
        self.add_data_group_window.show(self.dt_treestore, group)
    
    def match_datatree_val(self, model, path, iter, data):
        if model.get_value(iter, 0) == data[0]:
            data[1].append(path)
        return False         
    
    def dt_namecol_func(self, column, cell, model, iter):
        if model.iter_parent(iter) == None:
            name = model.get_value(iter, 0)
            cell.set_property('markup', "<b>" + name + "</b>")
        return
    
    def dt_select_func(self, path):
        if len(path) == 2:
            return True
        else:
            if len(path) == 3:
                parent_path = (path[0], path[1],)
                self.dt_treeview.set_cursor(parent_path)                
            return False
            
    def dg_select_func(self, path):
        if len(path) == 1:
            return True
        else:
            parent_path = (path[0],)
            self.dt_treeview.set_cursor(parent_path)
            return False
    
    def find_group_by_id(self, id):
        id_edit = id + ".."
        dg_iter = self.dg_treestore.get_iter_root()
        while dg_iter:
            curr_id = self.dg_treestore.get_value(dg_iter, 1)
            if id_edit == curr_id:
                group = self.dg_treestore.get_value(dg_iter, 4)
                return group
            dg_iter = self.dg_treestore.iter_next(dg_iter)
        return None
    
    def create_id(self, name):
        # Write code to generate R-compatible names
        return name
    
    def append_data_treeview(self, object, id):
        if self.main_window.r_eng.is_data_frame(id):
            data_sets_path = self.data_sets_ref.get_path()
            data_sets_iter = self.dt_treestore.get_iter(data_sets_path)
            
            object_type = "Data Frame"

            names = self.main_window.r_eng.get_dataframe_names(id)
            object_len = len(names)
            parent_iter = self.dt_treestore.append(data_sets_iter, \
                [object, id, object_type, object_len])
            for column in names:
                column_id = self.create_id(column)
                column_type = self.main_window.r_eng.get_type(column_id)
                column_len = self.main_window.r_eng.get_length(column_id)
                self.dt_treestore.append(parent_iter, [column, column_id, column_type,\
                    column_len])
                    
            count = self.dt_treestore.get_value(data_sets_iter, 3) + 1
            self.dt_treestore.set_value(data_sets_iter, 3, count)
        
        else:
            other_objects_path = self.other_objects_ref.get_path()
            other_objects_iter = self.dt_treestore.get_iter(other_objects_path)
            
            object_type = self.main_window.r_eng.get_type(id)
            object_len = self.main_window.r_eng.get_length(id)
            parent_iter = self.dt_treestore.append(other_objects_iter, \
                [object, id, object_type, object_len])

            count = self.dt_treestore.get_value(other_objects_iter, 3) + 1
            self.dt_treestore.set_value(other_objects_iter, 3, count)
        
    def update_data_view(self):
        """This function updates the data tab with new objects that have
        been added and removes objects that no longer exist."""
        data_objects_temp = self.main_window.r_eng.get_objects()
        new_objects = list(data_objects_temp - self.data_objects)
        for obj in new_objects:
            if obj.startswith("dg"):
                id = obj.split("..")[0]
                group = self.find_group_by_id(id)
                if group == None:
                    self.error.show_error("Error", "Data group for child object %s missing"%obj)
                    return
                n = self.main_window.r_eng.get_length(obj)
                obj_name = group.add_object(obj, n)
                self.edit_data_group(group, group.name)
                self.append_data_treeview(obj_name, obj)
            else:
                id = self.create_id(obj)
                self.append_data_treeview(obj, id)
                
        self.data_objects = self.data_objects | set(new_objects)
        
        old_objects = list(self.data_objects - data_objects_temp)
        if len(old_objects) > 0:
            for obj in old_objects:
                pathlist = []
                self.dt_treestore.foreach(self.match_datatree_val, \
                    (obj, pathlist))
                pathlist.reverse()
                other_objects_path = self.other_objects_ref.get_path()
                other_objects_iter = self.dt_treestore.get_iter(other_objects_path)
                data_sets_path = self.data_sets_ref.get_path()
                data_sets_iter = self.dt_treestore.get_iter(data_sets_path)
                for path in pathlist:
                    iter = self.dt_treestore.get_iter(path)
                    if self.dt_treestore.is_ancestor(other_objects_iter, iter):
                        count = int(self.dt_treestore.get_value(other_objects_iter, 3)) - 1
                        self.dt_treestore.set_value(other_objects_iter, 3, count)
                    else:
                        count = int(self.dt_treestore.get_value(data_sets_iter, 3)) - 1
                        self.dt_treestore.set_value(data_sets_iter, 3, count)
                    self.dt_treestore.remove(iter)
            self.data_objects = self.data_objects - set(old_objects)
        self.dt_treeview.show()
        
    def add_data_group(self, group):
        name = group.name
        id = group.id_str
        num_members = len(group.member_list)
        parent_iter = self.dg_treestore.append(None,[name, id, "", num_members, group])
        for member in group.member_list:
            memb_name = member.name
            memb_id = member.id
            memb_role = member.role
            memb_n = member.n
            self.dg_treestore.append(parent_iter,[memb_name, memb_id, memb_role, memb_n, None])
        
    def edit_data_group(self, group, old_name):
        parent_iter = self.dg_treestore.get_iter_root()
        while parent_iter:
            cur_name = self.dg_treestore.get_value(parent_iter, 0)
            if cur_name == old_name:
                break
            else:
                parent_iter = self.dg_treestore.iter_next(parent_iter)
        if parent_iter == None:
            self.error.show_error("Error", "Edited group missing from group list")
            return
        child_iter = self.dg_treestore.iter_children(parent_iter)
        cont = True
        while cont:
            cont = self.dg_treestore.remove(child_iter)
        
        name = group.name
        num_members = len(group.member_list)
        self.dg_treestore.set_value(parent_iter, 0, name)
        self.dg_treestore.set_value(parent_iter, 3, num_members)
        self.dg_treestore.set_value(parent_iter, 4, group)
        for member in group.member_list:
            memb_id = member.id
            memb_name = member.name
            memb_role = member.role
            n = self.main_window.r_eng.get_length(memb_id)
            self.dg_treestore.append(parent_iter,[memb_name, memb_id, memb_role, n, None]) 
        
    def __init__(self, parent_window, glade_gui):
        self.main_window = parent_window
        self.glade_gui = glade_gui
        self.add_data_sets_window = Add_data_set_window(self, self.glade_gui)
        self.add_data_group_window = Add_data_group_window(self, self.main_window, \
            self.glade_gui)      
        self.error = Error_dialog.Error_dialog()
        
        self.dt_treestore = gtk.TreeStore(TYPE_STRING, TYPE_STRING, \
            TYPE_STRING, TYPE_INT)
                    
        dt_iter = self.dt_treestore.append(None, \
            ["Data Frames","","",0])
        data_sets_path = self.dt_treestore.get_path(dt_iter)
        self.data_sets_ref = gtk.TreeRowReference(self.dt_treestore, \
            data_sets_path)            
        
        dt_iter = self.dt_treestore.append(None, \
            ["Other Objects","","",0])
        other_objects_path = self.dt_treestore.get_path(dt_iter)
        self.other_objects_ref = gtk.TreeRowReference(self.dt_treestore, \
            other_objects_path)            
            
        self.dt_treeview = glade_gui.get_widget("Data_objects_tree")
        self.dt_treeview.set_model(self.dt_treestore)
        dt_namecol = gtk.TreeViewColumn("Name")
        self.dt_treeview.append_column(dt_namecol)
        dt_namecell = gtk.CellRendererText()
        dt_namecol.pack_start(dt_namecell, True)
        dt_namecol.set_cell_data_func(dt_namecell, self.dt_namecol_func)
        
        dt_idcol = gtk.TreeViewColumn("ID")
        self.dt_treeview.append_column(dt_idcol)
        dt_idcell = gtk.CellRendererText()
        dt_idcol.pack_start(dt_idcell, True)

        dt_typecol = gtk.TreeViewColumn("Type")
        self.dt_treeview.append_column(dt_typecol)
        dt_typecell = gtk.CellRendererText()
        dt_typecol.pack_start(dt_typecell, True)
                
        dt_ncol = gtk.TreeViewColumn("n")
        self.dt_treeview.append_column(dt_ncol)
        dt_ncell = gtk.CellRendererText()
        dt_ncol.pack_start(dt_ncell, True)
        dt_namecol.add_attribute(dt_namecell, 'text', 0)
        dt_idcol.add_attribute(dt_idcell, 'text', 1)
        dt_typecol.add_attribute(dt_typecell, 'text', 2)
        dt_ncol.add_attribute(dt_ncell, 'text', 3)
        
        dt_selection = self.dt_treeview.get_selection()
        dt_selection.set_mode(gtk.SELECTION_SINGLE)
        dt_selection.set_select_function(self.dt_select_func)
        
        self.dg_treestore = gtk.TreeStore(TYPE_STRING, TYPE_STRING, TYPE_STRING, \
            TYPE_INT, TYPE_PYOBJECT)
        self.dg_treeview = glade_gui.get_widget("Data_groups_tree")
        self.dg_treeview.set_model(self.dg_treestore)
        dg_namecol = gtk.TreeViewColumn("Name")
        self.dg_treeview.append_column(dg_namecol)
        dg_namecell = gtk.CellRendererText()
        dg_namecol.pack_start(dg_namecell, True)

        dg_idcol = gtk.TreeViewColumn("ID")
        self.dg_treeview.append_column(dg_idcol)
        dg_idcell = gtk.CellRendererText()
        dg_idcol.pack_start(dg_idcell, True)

        dg_typecol = gtk.TreeViewColumn("Role")
        self.dg_treeview.append_column(dg_typecol)
        dg_typecell = gtk.CellRendererText()
        dg_typecol.pack_start(dg_typecell, True)
                
        dg_ncol = gtk.TreeViewColumn("n")
        self.dg_treeview.append_column(dg_ncol)
        dg_ncell = gtk.CellRendererText()
        dg_ncol.pack_start(dg_ncell, True)
        dg_namecol.add_attribute(dg_namecell, 'text', 0)
        dg_idcol.add_attribute(dg_idcell, 'text', 1)
        dg_typecol.add_attribute(dg_typecell, 'text', 2)
        dg_ncol.add_attribute(dg_ncell, 'text', 3)
        
        dg_selection = self.dg_treeview.get_selection()
        dg_selection.set_mode(gtk.SELECTION_SINGLE)
        dg_selection.set_select_function(self.dg_select_func)
        
        callbacks = {"on_Data_objects_remove" : self.on_data_objects_remove,\
            "on_Data_objects_add"    : self.on_data_objects_add,\
            "on_Data_objects_edit"   : self.on_data_objects_edit,\
            "on_Data_groups_remove" : self.on_data_groups_remove,\
            "on_Data_groups_add"    : self.on_data_groups_add,\
            "on_Data_groups_edit"   : self.on_data_groups_edit,\
            "on_Data_groups_tree_row_activated" : self.on_data_groups_activated,\
            "on_Data_objects_tree_row_activated" : self.on_data_objects_activated}
        self.glade_gui.signal_autoconnect(callbacks)
        
        self.data_objects_edit_button = self.glade_gui.get_widget("Data_objects_edit")
        self.data_objects_remove_button = self.glade_gui.get_widget("Data_objects_remove")
        self.data_groups_edit_button = self.glade_gui.get_widget("Data_groups_edit")
        self.data_groups_remove_button = self.glade_gui.get_widget("Data_groups_remove")
